const puppeteer = require('puppeteer-core');
const fs = require('fs');
const path = require('path');

const Config = require('./Config');

const { sleep } = require('./Helper')

class BrowserManager
{
    /**
     * @type {import('puppeteer-core').Browser | null}
     */
    browser = null;
    constructor()
    {

    }

    /**
     * 启动浏览器
     * @param {boolean} [headless=false]
     * @returns {Promise<import('puppeteer-core').Browser>}
     */
    async launchBrowser(headless = false)
    {
        if (this.browser !== null) await this.browser.close();
        this.browser = await puppeteer.launch({
            executablePath: Config.chromeFile,
            headless: headless,
            args: ['--start-maximized','--disable-gpu', '--disable-setuid-sandbox', '--no-sandbox', '--no-zygote'],
            ignoreDefaultArgs: ["--enable-automation"],
            devtools: false, // 自动打开devtool
            defaultViewport: {
                width: 1500,
                height: 800
            }
        });
        return this.browser;
    }



    /**
     * 初始化防检测环境（Stealth）——在 page 创建后尽快调用（在 goto 之前）
     * @param {import('puppeteer-core').Page} page - Puppeteer 页面对象
     * @returns {Promise<import('puppeteer-core').Page>}
     */
    async stealthInit(page)
    {
        await page.evaluateOnNewDocument(() => {
            try {
                delete navigator.webdriver;
                Object.defineProperty(navigator, 'webdriver', {
                    get: () => false
                });
            } catch (e) {
                // 如果删除或定义失败，忽略
                console.warn('无法覆盖 navigator.webdriver', e);
            }
        });
        await page.setUserAgent(Config.userAgent);
        await page.evaluateOnNewDocument(() => {
            Object.defineProperty(navigator, 'webdriver', { get: () => false });
            Object.defineProperty(navigator, 'plugins', {
                get: () => [
                    {
                        0: {type: "application/x-google-chrome-pdf", suffixes: "pdf", description: "Portable Document Format", enabledPlugin: Plugin},
                        description: "Portable Document Format",
                        filename: "internal-pdf-viewer",
                        length: 1,
                        name: "Chrome PDF Plugin"
                    },
                    {
                        0: {type: "application/pdf", suffixes: "pdf", description: "", enabledPlugin: Plugin},
                        description: "",
                        filename: "mhjfbmdgcfjbbpaeojofohoefgiehjai",
                        length: 1,
                        name: "Chrome PDF Viewer"
                    },
                    {
                        0: {type: "application/x-nacl", suffixes: "", description: "Native Client Executable", enabledPlugin: Plugin},
                        1: {type: "application/x-pnacl", suffixes: "", description: "Portable Native Client Executable", enabledPlugin: Plugin},
                        description: "",
                        filename: "internal-nacl-plugin",
                        length: 2,
                        name: "Native Client"
                    }
                ],
            });
            // 伪造 languages
            Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });

            // 如果需要伪造 chrome 对象（某些检测会检测 window.chrome）
            // eslint-disable-next-line no-undef
            try {
                window.chrome = window.chrome || { runtime: {}, loadTimes: () => {}, csi: () => {} };
            } catch (e) { /* ignore */ }
        })
        page.on('error', async (err) => {
            console.error('页面崩溃:', err);
            try {
                await page.evaluate(() => {
                    history.go(0);  // 或者 location.reload()
                });
            } catch (e) {
                console.error('刷新页面失败:', e);
            }
        });
        return page;
    }

    /**
     * 打开新页面（自动做 stealth）并访问 url，可执行可选的 jsCode（字符串）
     * @param {string} url 网址
     * @param {string} cookieValue 登录cookieValue
     * @param {string|Function} [jsCode] - 可选：要在页面上下文执行的 JS，字符串会被 eval 执行（注意风险）
     * @returns {Promise<import('puppeteer-core').Page>}
     */
    async openPage(url,cookieValue = '',jsCode = '')
    {
        if (!this.browser) throw new Error('请先执行 launchBrowser(); ');

        const page = await this.browser.newPage();
        if (cookieValue !== '')
        {
            const cookie = {
                name: Config.cookieName,
                value: cookieValue, // 用你完整的值
                domain: 'music.163.com',   // 根据目标站点调整，最常见是 music.163.com
                path: '/',
                httpOnly: false,          // 根据实际 cookie 属性调整
                secure: true,            // 如果目标站使用 https，可设为 true
                sameSite: 'Lax',          // 'Strict' | 'Lax' | 'None'
                // expires: Math.floor(Date.now()/1000) + 60*60*24*30 // 选填：到期时间，用秒为单位的 UNIX 时间戳
            };

            await page.setCookie(cookie); // 在 goto 之前调用
        }



        this.stealthInit(page);
        await page.goto(url, {timeout: 600000 });

        // 如果传入了 jsCode（字符串或函数），在页面上下文执行它
        if (jsCode) {
            if (typeof jsCode === 'function') {
                // 直接把函数序列化到浏览器端执行（无外部闭包）
                await page.evaluate(jsCode);
            } else if (typeof jsCode === 'string') {
                // 警告：eval 有风险。确保你信任 jsCode 来源。
                await page.evaluate((code) => {
                    // eslint-disable-next-line no-eval
                    return eval(code);
                }, jsCode);
            }
        }
        return page;
    }

    /**
     * 查找 selector 并返回 ElementHandle（兼容 iframe）
     * @param {import('puppeteer-core').Page} page - Puppeteer 页面对象
     * @param {string} selector - CSS 选择器
     * @param {number} [waitTimeout=3000] - 等待选择器出现的时间（毫秒）
     * @returns {Promise<import('puppeteer-core').ElementHandle|null>} - 找到返回 ElementHandle，找不到返回 null
     */
    async getElementHandleBySelector(page, selector, waitTimeout = 3000) {
        // 尝试主文档
        // 主文档
        try {
            const handle = await page.waitForSelector(selector, { timeout: waitTimeout });
            if (handle) return handle;
        } catch(e) { }

        // 遍历 frame
        for (const frame of page.frames()) {
            try {
                const handle = await frame.waitForSelector(selector, { timeout: waitTimeout });
                if (handle) return handle;
            } catch(e) { }
        }

        return null;
    }


    async close() {
        if (this.browser) {
            await this.browser.close();
            this.browser = null;
        }
    }

}


module.exports = BrowserManager;